﻿#include "vcl_stl.h"

#include "h_base.h"

#include "h_lz77.h"
#include "h_lz77_old.h"

namespace h_base
{

string EnvEvaluate(const string &Str)
{
#if defined(BK_AIX) || defined(BK_LINUX)
   int i, j;
   char *Env;
   string Result;
   string EnvName;

   for ( i = 0; ; )
   {
      j = Str.find('$', i);
      if ( j == string::npos )
      {
         Result += Str.substr(i);
         break;
      }
      Result += Str.substr(i, j - i);
      i = j + 1;
      if ( Str[i] == '{' )
      {
         i++;
         j = Str.find('}', i);
         if ( j == string::npos )
         {
            break;
         }
         EnvName = Str.substr(i, j - i);
         ToUpper(EnvName);
         Env = getenv(EnvName.c_str());
         j++;
      }
      else
      {
         for ( j = i; ; j++ )
         {
            if ( Str[j] != '_' && !isalnum(Str[j]) )
            {
               break;
            }
         }
         EnvName = Str.substr(i, j - i);
         ToUpper(EnvName);
         Env = getenv(EnvName.c_str());
      }
      if ( Env != NULL )
      {
         Result += Env;
      }
      i = j;
   }

   return Result;
#else
   return Str;
#endif
}

bool CharInStr(char c, const char *Str)
{
   const char *s;

   for( s = Str; *s != '\0' && *s != c; s++ )
      ;

   return *s == c;
}

int ReadLine(FILE *f, char *s, int MaxLen, bool TabToSpace)
{
   int i;
   int c;

   for ( i = 0; i < MaxLen; )
   {
      c = fgetc(f);
      if ( ( c == '\t' && TabToSpace ) || c == '\0' )
      {
         c = ' ';
      }
      if ( c == EOF || c == '\n' )
      {
         break;
      }
      s[i++] = c;
   }

   s[i] = '\0';

   if ( i == MaxLen )
   {
      for ( ; ; )
      {
         c = fgetc(f);
         if ( c == EOF || c == '\n' )
         {
            break;
         }
      }
   }

   if ( c == EOF && i == 0 )
   {
      return -1;
   }
   else
   {
      return i;
   }
}

int ReadWord(const char *s, char *w, const char *separators, int MaxLen)
{
   int i, j;

   i = 0;

   if ( CharInStr(' ', separators) )
   {
      for ( ; s[i] == ' '; i++ )
         ;
   }

   j = 0;

   if ( s[i] == '\0' )
   {
      w[0] = '\0';
      return 0;
   }

   if ( CharInStr(s[i], separators) )
   {
      w[j++] = s[i++];
      w[j] = '\0';
      return i;
   }

   for ( ; j < MaxLen && s[i] != '\0' && !CharInStr(s[i], separators); )
   {
      w[j++] = s[i++];
   }

   w[j] = '\0';
   return i;
}

void SplitString(const string &s, char Delimiter,
   vector<string> &Text, bool TrimSpace)
{
   int i, j;
   int First; // 每一段的第一个非空格字符位置
   int Last = 0;  // 每一段的最后一个非空格字符位置

   Text.clear();

   if ( Delimiter == '\n' && s[0] == '\0' )
   {
      return;
   }

   for ( First = -1, j = 0, i = 0; ; )
   {
      if ( s[i] == '\0' )
      {
         if ( TrimSpace && First != -1 )
         {
            Text.push_back(s.substr(First, Last - First + 1));
         }
         else
         {
            Text.push_back(s.substr(j, i - j));
         }
         break;
      }
      if ( s[i] == Delimiter )
      {
         if ( TrimSpace && First != -1 )
         {
            Text.push_back(s.substr(First, Last - First + 1));
            First = -1;
         }
         else
         {
            Text.push_back(s.substr(j, i - j));
         }
         i++;
         j = i;
         continue;
      }
      if ( TrimSpace && s[i] != ' ' )
      {
         Last = i;
         if ( First == -1 )
         {
            First = i;
         }
      }
      i++;
   }
}

string JoinStrings(const vector<string> &Vec, char Delimiter)
{
   string Result;

   for ( int i = 0; i < Vec.size(); i++ )
   {
      if ( i > 0 )
      {
         Result += Delimiter;
      }
      Result += Vec[i];
   }

   return Result;
}

void SplitPath(const string &Path, string &DirName, string &BaseName,
   string &Postfix)
{
   int Pos;

   Pos = Path.rfind("/");

   if ( Pos == string::npos )
   {
      DirName = ".";
      BaseName = Path;
   }
   else
   {
      DirName = Path.substr(0, Pos);
      BaseName = Path.substr(Pos + 1);
   }

   Pos = BaseName.rfind(".");

   if( Pos == string::npos )
   {
      Postfix = "";
   }
   else
   {
      Postfix = BaseName.substr(Pos + 1);
      BaseName = BaseName.substr(0, Pos);
   }
}

void RightTrim(string &Str)
{
   int Pos;

   Pos = Str.find_last_not_of(" ");

   if( Pos == string::npos )
   {
      Str.resize(0);
   }
   else
   {
      Str.resize(Pos + 1);
   }
}

void ToUpper(string &Str)
{
   for ( int i = 0; i < Str.length(); i++ )
   {
      if ( Str[i] >= 'a' && Str[i] <= 'z' )
      {
         Str[i] -= 'a' - 'A';
      }
   }
}

void ToLower(string &Str)
{
   for ( int i = 0; i < Str.length(); i++ )
   {
      if ( Str[i] >= 'A' && Str[i] <= 'Z' )
      {
         Str[i] += 'a' - 'A';
      }
   }
}

void ToUpper(char *s)
{
   for ( ; *s != '\0'; s++ )
   {
      if ( *s >= 'a' && *s <= 'z' )
      {
         *s -= 'a' - 'A';
      }
   }
}

void ToLower(char *s)
{
   for ( ; *s != '\0'; s++ )
   {
      if ( *s >= 'A' && *s <= 'Z' )
      {
         *s += 'a' - 'A';
      }
   }
}

static int _MatchToken(const char *Line, int &Start, const char *Tokens[])
{
   int i;
   const char *s1;
   const char *s2;

   for ( i = 0; Tokens[i] != NULL; i++ )
   {
      s1 = Line + Start;
      s2 = Tokens[i];
      for ( ; *s1 != '\0' && *s2 != '\0' && *s1 == *s2; s1++, s2++ )
         ;
      if ( *s2 == '\0' )
      {
         Start += s2 - Tokens[i];
         return i;
      }
   }

   return -1;
}

bool TextFileCompress(const string &SrcFileName,
   const string &DesFileName)
{
   FILE *fin, *fout;

   fin = _wfopen(UnicodeString(UTF8String(SrcFileName.c_str())).c_str(), L"rt");

   if ( fin == NULL )
   {
      return false;
   }

   fout = _wfopen(UnicodeString(UTF8String(DesFileName.c_str())).c_str(), L"wb");

   if ( fout == NULL )
   {
      fclose(fin);
      return false;
   }

   if ( Lz77CompressFile(fin, fout) != 0 )
   {
      fclose(fin);
      fclose(fout);
      return false;
   }

   fclose(fin);
   fclose(fout);
   return true;
}

bool TextFileCompress_old(const string &SrcFileName,
   const string &DesFileName)
{
   FILE *fin, *fout;

   fin = _wfopen(UnicodeString(UTF8String(SrcFileName.c_str())).c_str(), L"rt");

   if ( fin == NULL )
   {
      return false;
   }

   fout = _wfopen(UnicodeString(UTF8String(DesFileName.c_str())).c_str(), L"wb");

   if ( fout == NULL )
   {
      fclose(fin);
      return false;
   }

   if ( Lz77CompressFile_old(fin, fout) != 0 )
   {
      fclose(fin);
      fclose(fout);
      return false;
   }

   fclose(fin);
   fclose(fout);
   return true;
}

bool TextFileDecompress(const string &SrcFileName,
   const string &DesFileName)
{
   FILE *fin, *fout;

   fin = _wfopen(UnicodeString(UTF8String(SrcFileName.c_str())).c_str(), L"rb");

   if ( fin == NULL )
   {
      return false;
   }

   fout = _wfopen(UnicodeString(UTF8String(DesFileName.c_str())).c_str(), L"wb");

   if ( fout == NULL )
   {
      fclose(fin);
      return false;
   }

   if ( Lz77DecompressFile(fin, fout) != 0 )
   {
      fclose(fin);
      fclose(fout);
      return false;
   }

   fclose(fin);
   fclose(fout);
   return true;
}

bool TextFileDecompress_old(const string &SrcFileName,
   const string &DesFileName)
{
   FILE *fin, *fout;

   fin = _wfopen(UnicodeString(UTF8String(SrcFileName.c_str())).c_str(), L"rb");

   if ( fin == NULL )
   {
      return false;
   }

   fout = _wfopen(UnicodeString(UTF8String(DesFileName.c_str())).c_str(), L"wb");

   if ( fout == NULL )
   {
      fclose(fin);
      return false;
   }

   if ( Lz77DecompressFile_old(fin, fout) != 0 )
   {
      fclose(fin);
      fclose(fout);
      return false;
   }

   fclose(fin);
   fclose(fout);
   return true;
}

unsigned int Hash(const void *Buf, int Len)
{
   int i;
   const unsigned char *s = static_cast<const unsigned char *>(Buf);
   unsigned int Result;

   for( Result = 0, i = 0; i < Len; i++, s++ )
      Result = Result * 5 + *s + 1;

   return Result;
}

int StrToInt(const char *Str)
{
   int Result = 0;

   sscanf(Str, "%d", &Result);
   return Result;
}

int StrToInt(const string &Str)
{
   return StrToInt(Str.c_str());
}

int HexStrToInt(const char *Str)
{
   int Result = 0;

   sscanf(Str, "%x", &Result);
   return Result;
}

float StrToFloat(const char *Str)
{
   float Result = 0;

   sscanf(Str, "%f", &Result);
   return Result;
}

double StrToDouble(const char *Str)
{
   double Result = 0;

   sscanf(Str, "%lf", &Result);
   return Result;
}

long double StrToLongDouble(const char *Str)
{
   long double Result = 0;

   sscanf(Str, "%Lf", &Result);
   return Result;
}

// class HStream
  
HStream::~HStream()
{
}

HFileStream::HFileStream(FILE *File)
   : HStream()
{
   FFile = File;
   FRecLen = -1;

   if ( FRecLen != -1 )
   {
      FLine = (char*)malloc(FRecLen);
   }
   else
   {
      FLine = NULL;
   }
}

HFileStream::~HFileStream()
{
   if ( FLine != NULL )
   {
      free(FLine);
      FLine = NULL;
   }
}

int HFileStream::ReadLine(char *Line, int MaxLen, bool TabToSpace)
{
   if ( FFile == NULL )
   {
      return -1;
   }

   if ( FRecLen == -1 )
   {
      return h_base::ReadLine(FFile, Line, MaxLen, TabToSpace);
   }

   if ( fread(FLine, FRecLen, 1, FFile) != 1 )
   {
      return -1;
   }

   int Len = min(FRecLen, MaxLen);

   for ( int i = 0; i < Len; i++ )
   {
      if ( FLine[i] == '\0' )
      {
         FLine[i] = ' ';
         continue;
      }
#if !defined(BK_S390)
      if ( FLine[i] == '\r' || FLine[i] == 0x1a )
      {
         FLine[i] = ' ';
      }
#endif
      if ( TabToSpace )
      {
         if ( FLine[i] == '\t' )
         {
            FLine[i] = ' ';
         }
      }
   }

   memcpy(Line, FLine, Len);
   Line[Len] = '\0';
   return Len;
}

void HFileStream::WriteLine(const char *Line)
{
   if ( FFile == NULL )
   {
      return;
   }

   if ( FRecLen == -1 )
   {
      if ( fprintf(FFile, "%s\n", Line) < 0 )
      {
         fprintf(stderr, "fprintf fail, errno = %d\n", errno);
         exit(12);
      }
      return;
   }

   int Len = strlen(Line);

   if ( Len < FRecLen )
   {
      memcpy(FLine, Line, Len);
      memset(FLine + Len, ' ', FRecLen - Len);
   }
   else
   {
      memcpy(FLine, Line, FRecLen);
   }

   if ( fwrite(FLine, FRecLen, 1, FFile) != 1 )
   {
      fprintf(stderr, "fwrite fail, errno = %d\n", errno);
      exit(12);
   }
}

int HFileStream::ReadRec(char *Buf, int MaxLen)
{
   if ( FFile == NULL || FRecLen == -1 )
   {
      return -1;
   }

   if ( fread(FLine, FRecLen, 1, FFile) != 1 )
   {
      return -1;
   }

   if ( MaxLen > FRecLen )
   {
      memcpy(Buf, FLine, FRecLen);
      memset(Buf + FRecLen, ' ', MaxLen - FRecLen);
      return FRecLen;
   }
   else
   {
      memcpy(Buf, FLine, MaxLen);
      return MaxLen;
   }
}

int HFileStream::WriteRec(const char *Rec, int Len)
{
   if ( FRecLen == -1 )
   {
      if ( fwrite(Rec, Len, 1, FFile) != 1 )
      {
         return -1;
      }
      else
      {
         return 0;
      }
   }

   if ( Len < FRecLen )
   {
      memcpy(FLine, Rec, Len);
      memset(FLine + Len, ' ', FRecLen - Len);
   }
   else
   {
      memcpy(FLine, Rec, FRecLen);
   }

   fwrite(FLine, FRecLen, 1, FFile);
   return 0;
}

HMemStream::HMemStream(void *Buf, int Len)
   : HStream(), FPos(0)
{
   if ( Len == 0 )
   {
      return;
   }

   FMem.resize(Len);
   memcpy(&FMem[0], Buf, Len);
}

int HMemStream::ReadLine(char *Line, int MaxLen, bool TabToSpace)
{
   if ( FPos == FMem.size() )
   {
      return -1;
   }

   int i;

   for ( i = 0; FPos < FMem.size() && i < MaxLen &&
                FMem[FPos] != '\n'; FPos++, i++ )
   {
      if ( TabToSpace && FMem[FPos] == '\t' )
      {
         Line[i] = ' ';
      }
      else
      {
         Line[i] = FMem[FPos];
      }
   }

   if ( i == MaxLen )
   {
      for ( ; FPos < FMem.size() && FMem[FPos] != '\n'; FPos++ )
         ;
      if ( FPos < FMem.size() )
      {
         FPos++;
      }
   }
   else
   {
      if ( FPos < FMem.size() )
      {
         FPos++;
      }
   }

   Line[i] = '\0';
   return i;
}

void HMemStream::WriteLine(const char *Line)
{
   int CurrLen = FMem.size();
   int Len = strlen(Line);

   FMem.resize(CurrLen + Len + 1);
   memcpy(&FMem[0] + CurrLen, Line, Len);
   FMem[CurrLen + Len] = '\n';
}

char *HMemStream::GetBuf(void)
{
   return &FMem[0];
}

int HMemStream::GetLength(void)
{
   return FMem.size();
}

}; // namespace h_base
